function vNode(el, attrs = {}, type = "element") {
    if (typeof (attrs) == 'string') {
        type = attrs
        attrs = {}
    }
    this.el = undefined
    this.type = undefined
    this.attrs = {}
    this.text = undefined
    this.dataSource = undefined
    this.childs = undefined
    this.condition= undefined
    this.parent = undefined
    return this.create(el, attrs, type)
}
vNode.prototype._PROXY = function () {
    return new Proxy(this, {
        get(target, property) {
            if (property in target)
                return Reflect.get(target, property)
            else
                throw new ReferenceError(`${property} does not exist.`)
        },
        set(target, property, value) {
            if (property in target) {
                switch (property) {
                    case "type": {
                        if (value != "element" && value != 'slots' && value != "scopedslots") {
                            throw new ReferenceError(`vNode 'type' must set (element|slots|scopedslots)`)
                        }
                        else {
                            value = value
                        }
                        break;
                    }
                }
                return Reflect.set(target, property, value)
            } else {
                throw new ReferenceError(`'${property}' does not exist.`)
            }
        }
    })
}

vNode.prototype.create = function (el, attrs, type) {
    if (typeof (attrs) == 'string') {
        type = attrs
        attrs = {}
    }
    let v = this._PROXY()
    v.el = el
    v.type = type
    v.attrs = attrs
    return v
}

/*Method: appendChild
    append child vNode.
  Args: 
    el: Class<string>, DOM(HTML DOM, VUE DOM) name
    attrs: Class<{}>, vue createElement second parameter. see more: https://cn.vuejs.org/v2/guide/render-function.html#%E6%B7%B1%E5%85%A5%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1
    type: Class<String>, must lower, element | slots |scopedslots
  Return:
    Class<vNode>, it is the new child vNode Object.
 */
vNode.prototype.appendChild = function (el, attrs = {}, type = "element") {
    if (typeof (attrs) == 'string') {
        type = attrs
        attrs = {}
    }
    if (this._PROXY().childs == undefined) {
        this._PROXY().childs = []
    }
    let v = new vNode(el, attrs, type)
    v._PROXY().parent = this
    this._PROXY().childs.push(v)
    return v
}

vNode.prototype.appendChildNode=function(v){
    if (this._PROXY().childs == undefined) {
        this._PROXY().childs = []
    }
    if(Array.isArray(v)){
        v.forEach((childNode)=>{
            this._PROXY().childs.push(childNode)
        })
        return this
    }
    else{
        this._PROXY().childs.push(v)
        return v
    }
}

vNode.prototype.getParent = function () {
    return this._PROXY().parent
}
/*Method: addAttribute
  Desc: add node attribute.
  Args:
    key: Class<String>, vue createElement sencond parameter({}) key.
    value: Class<Any>, attribute value,
    override: Class<Boolen>, default false, if it is true, when the key has existed then the new value will override old value. 
  Return:
    this
 */
vNode.prototype.addAttribute = function (key, value, override = false) {
    let condition = true
    if (this._PROXY().attrs.hasOwnProperty(key)) {
        if (!override) {
            throw new TypeError(`'${key}' has ready, if you want set it please set parameter 'override' true.`)
        } else {
            condition = true
        }
    }
    this._PROXY().attrs[key] = value
    return this
}

/*Method: setValue
   Desc: set vNode value.
   Args: 
    v: Class<any>
   Return: 
    this 
 */
vNode.prototype.setValue = function (v) {
    this._PROXY().text = v
    return this
}
vNode.prototype.setCondition= function(v){
    this._PROXY().condition=v
    return this
}
vNode.prototype.setDataSource = function (v) {
    this._PROXY().dataSource = v
    return this
}

export default vNode